const buffer = require("buffer");

/**
 * 进制转换器：
 *    JS只有五种数据基本数据类型 String 、 Number 、 Boolean 、Null 、Undefined
 *        Number：在 JavaScript 中，Number 类型通常是双精度浮点数，这意味着它占用 8 个字节（64位）的内存空间。
 *       String：字符串在 JavaScript 中是不可变的，每个字符串通常占用 4-12 字节的内存（取决于字符串的长度）。
 *       Boolean：布尔值通常占用 1 字节的内存空间。
 *       Null：null 值专门用于表示空值或无值，通常只占用 0 字节内存。
 *       Undefined：undefined 值表示变量已声明但尚未赋值，通常也只占用 0 字节内存。
 *  为保证数据和C++的数据类型：Uint 、int 、Long int 、Long Long int 、double 、float类型相同，需要使用buffer缓冲区模拟这些数据类型
 *  然后再发送出去
 *  注意：发送数据全部采用小端形式！
 *  注意：当数据长度超过范围时，会将超出部分的高位截去，只留下低位存入
 * @param num  传过来需要进行进制转换的数据
 * @param type  数据类型
 * @returns {Buffer} 转换成功输出缓冲区，转换失败输出null
 */
function num2Buffer(num , type) {
    type = type.toUpperCase()
    // UINT8——0-255
    if (type === 'UINT8') {
        const buffer = new ArrayBuffer(1);
        const view = new DataView(buffer);
        view.setUint8(0 , num )
        return Buffer.from(view.buffer)
    //     INT8——-128-127
    } else if (type === 'INT8') {
        const buffer = new ArrayBuffer(1);
        const view = new DataView(buffer);
        view.setInt8(0 , num)
        return Buffer.from(view.buffer)
    } else if (type === 'UINT16') {
        const buffer = new ArrayBuffer(2);
        const view = new DataView(buffer);
        view.setUint16(0 , num ,true)
        return Buffer.from(view.buffer)
    } else if (type === 'INT16') {
        const buffer = new ArrayBuffer(2);
        const view = new DataView(buffer);
        view.setInt16(0 , num,true)
        return Buffer.from(view.buffer)
    } else if (type === 'UINT32') {
        const buffer = new ArrayBuffer(4);
        const view = new DataView(buffer);
        view.setUint32(0 , num ,true)
        return Buffer.from(view.buffer)
    } else if (type === 'INT32') {
        const buffer = new ArrayBuffer(4);
        const view = new DataView(buffer);
        view.setInt32(0 , num ,true)
        return Buffer.from(view.buffer)
    } else if (type === 'FLOAT') {
        const buffer = new ArrayBuffer(4);
        const view = new DataView(buffer);
        view.setFloat32(0 , num ,true)
        return Buffer.from(view.buffer)
    } else if (type === 'UINT64') {
        num = BigInt(num)
        const buffer = new ArrayBuffer(8);
        const view = new DataView(buffer);
        view.setBigUint64(0 , num ,true)
        return Buffer.from(view.buffer)
    } else if (type === 'INT64') {
        num = BigInt(num)
        const buffer = new ArrayBuffer(8);
        const view = new DataView(buffer);
        view.setBigInt64(0 , num ,true)
        return Buffer.from(view.buffer)
    } else if (type === 'DOUBLE') {
        const buffer = new ArrayBuffer(8);
        const view = new DataView(buffer);
        view.setFloat64(0 , num ,true)
        return Buffer.from(view.buffer)
    } else if (type.slice(0 , 4) === 'NONE') {
        const buffer = new ArrayBuffer(+type.slice(4));
        const view = new DataView(buffer);
        return Buffer.from(view.buffer)
    } else {
        console.log(`输入的数据类型为:${type} , 转换函数未收录该功能`)
        return null
    }
}
/**
 * 将numberToBuffer的数据反解码，获取具体数字
 * @param buffer
 * @param type
 * @param begin
 * @param end
 * @returns {bigint|number|null}
 */
// buffer2Num(Buffer.from([0x00 , 0x00]) , 'UINT16')
// 12个字节 3个4字节 INT32 INT32 INT32
function buffer2Num(buffer = Buffer.alloc(0 , 0 , 'hex'), type , begin , end){
    type = type.toUpperCase()
    const buffer1 = Buffer.from(buffer.subarray(begin, end));
    // 创建一个与Buffer数据长度相同的ArrayBuffer实例
    const arrayBuffer = new ArrayBuffer(buffer1.length);
    // 创建一个Uint8Array视图，以便操作ArrayBuffer
    const uint8Array = new Uint8Array(arrayBuffer);
    // 将Buffer的数据逐字节复制到Uint8Array（ArrayBuffer）
    for (let i = 0; i < buffer1.length; i++) {
        uint8Array[i] = buffer1[i];
    }
    const view = new DataView(arrayBuffer);

    if (type === 'UINT8') {
        return view.getUint8(0)
    } else if (type === 'INT8') {
        return view.getInt8(0)
    } else if (type === 'UINT16') {
        return view.getUint16(0 , true)
    } else if (type === 'INT16') {
        return view.getInt16(0 , true)
    } else if (type === 'UINT32') {
        return view.getUint32(0 , true)
    } else if (type === 'INT32') {
        return view.getInt32(0 , true)
    } else if (type === 'FLOAT') {
        return view.getFloat32(0 , true)
    } else if (type === 'UINT64') {
        return view.getBigUint64(0 , true)
    } else if (type === 'INT64') {
        return view.getBigInt64(0 , true)
    } else if (type === 'DOUBLE') {
        return view.getFloat64(0 , true)
    } else if (type.slice(0 , 4) === 'NONE') {
        return 0
    } else {
        console.log(`输入的数据类型为:${type} , 转换函数未收录该功能`)
        return null
    }
}
/**
 * 将buffer类型转成string类型的字符串
 * @param buffer
 * @param begin
 * @param end
 */
function buffer2String(buffer , begin , end) {
    const buffer1 = Buffer.from(buffer.subarray(begin, end));
    return buffer1.toString('utf8')
}

/**
 * 遍历数组，获取数组元素
 * @param obj
 * @param callback
 */
function printObj(obj , callback) {
    for (let key in obj) {
        if (obj[key] !== null) console.log(`${key}: ${obj[key].toString('hex')}`) // 递归执行体
        else console.log(`${key}: null`)
    }
}

/**
 * 将对象形式的缓冲区合并在一起，形成一个大的缓冲区，返回值为新的buffer
 * @param obj
 * @returns {Buffer|null}
 */
function obj2buffer(obj = {}) {
    for (let objKey in obj) {
        if (obj[objKey] === null) {
            // console.log(`${objKey} 是空字符串，无法进行拼接`)
            return null
        }
        else {
            let buffers = [Buffer.alloc(0 , 0 , "hex")]
            buffers = Object.values(obj)
            let newBuffer = Buffer.concat(buffers)
            // console.log(`新拼接成的buffer为: ${newBuffer.toString('hex')}`)
            return newBuffer
        }
    }
}

/**
 * 判断对象是否赋值完毕，只有当数据全部不为null时才能发送
 * @param obj
 * @returns {boolean}
 */
function readyToSend(obj) {
    for (let objKey in obj) {
        if (obj[objKey] === null) {
            return false
        }
    }
    return true
}

/**
 * 判断对象中没有赋值的元素
 * @param obj
 * @returns {boolean}
 */
function findUnassigned(obj) {
    for (let objKey in obj) {
        if (obj[objKey] === null) {
            console.log(`${objKey}未赋值`)
        }
    }
    return true
}

/**
 * 获取对象对应的缓冲区数据长度
 * @param obj
 * @returns {unknown}
 */
function getBufferLength(obj) {
    let buffers = Object.values(obj)
    let sum = 0
    for (let i = 0; i < buffers.length; i++) {
        if (buffers[i] !== null)
            sum += buffers[i].length
    }
    return sum
}

/**
 * 快速打印buffer中的数据
 * @param buffer
 */
function printBuffer(buffer) {
    // 获取缓冲区成都
    const length = buffer.length;

    // Print header for indices
    let header = '索引 ';
    for (let i = 1; i <= length; i++) {
        if (i === 13 || i === 38)
            header += i.toString().padStart(3, '-');
        else
            header += i.toString().padStart(3, ' ');
    }
    console.log(header);

    // Print buffer content in hex
    let content = '数据  ';
    for (let i = 0; i < length; i++) {
        if (i === 11 || i === 36)
            content += buffer[i].toString(16).padStart(2, '0') +  '-';
        else
            content += buffer[i].toString(16).padStart(2, '0') +  ' ';
    }
    console.log(content);
}
/**
 * node没有原生的buffer分割函数，buffer2String函数返回的是一个字符串，
 * 这里把buffer函数改造一下，改造成可以返回buffer的函数
 * @param buffer
 * @param begin
 * @param end
 * @returns {Buffer}
 */
function splitBuffer(buffer = Buffer.alloc(0 , 0 , "hex"), begin = 0, end) {
    let bufferStr = buffer.toString('hex' , begin , end)
    return Buffer.from(bufferStr , "hex")
}

/**
 * 获取报文的报文头
 * @param buffer
 * @returns {Buffer}
 */
function getMessageHeader(buffer =Buffer.alloc(0 , 0 , "hex")) {
    return splitBuffer(buffer , 0 , 12)
}
/**
 * 获取报文的报文体
 * @param buffer
 * @returns {Buffer}
 */
function getMessageBody(buffer =Buffer.alloc(0 , 0 , "hex")) {
    return splitBuffer(buffer , 12)
}
/**
 * 获取报文的报文参数
 * @param buffer
 * @returns {Buffer}
 */
function getMessageParams(buffer =Buffer.alloc(0 , 0 , "hex")) {
    return splitBuffer(buffer , 37 , buffer.length-1)
}
/**
 * 获取报文的报文类型
 * @param buffer
 * @returns {number}
 */
function getMessageParamsType(buffer =Buffer.alloc(0 , 0 , "hex")) {
    return parseInt(splitBuffer(buffer , 36 , 37).toString('hex') , '16')
}

/**
 * 计算校验位
 * @param messageBody
 * @returns {Buffer}
 */
function getCheck(messageBody = {}) {
    let sum = 0
    for (const messageBodyKey in messageBody) {
        if (messageBody[messageBodyKey] !== null) {
            for (let i = 0; i < messageBody[messageBodyKey].length; i++) {
                sum += messageBody[messageBodyKey][i]
            }
        }
    }
    let buffer = Buffer.alloc(1); // 创建一个1字节的buffer
    // 将数的低8位存入Buffer中
    buffer[0] = sum & 0xFF;
    // 按位取反
    buffer[0] = ~buffer[0] & 0xFF;
    return buffer
}

/**
 * 雷达校验码
 * @returns {Buffer}
 * @param messageBody
 */
function getCheckNormal(messageBody = {}) {
    let sum = 0
    for (const messageBodyKey in messageBody) {
        if (messageBody[messageBodyKey] !== null) {
            for (let i = 0; i < messageBody[messageBodyKey].length; i++) {
                sum += messageBody[messageBodyKey][i]
            }
        }
    }
    let buffer = Buffer.alloc(1); // 创建一个1字节的buffer
    // 将数的低8位存入Buffer中
    buffer[0] = sum & 0xFF;
    // 将数的低8位存入Buffer中
    return buffer
}
// function judgeCheckNormal(buffer = Buffer.alloc(0 , 0 , 'hex')){
//     let messageBody = getMessageBody(buffer)
//     let sum = 0;
//     for (let i = 0; i <messageBody.length-1 ; i++) {
//         sum+= messageBody[i]
//     }
//     //检查累加和是否等于5
//     if (sum===5){
//         console.log("校验和"+sum+"校验通过")
//         return true
//     }
//     else{
//         console.log("校验和"+sum+"校验不通过")
//         return false
//     }
// }
/**
 * 判定校验位
 * @param buffer
 */
function judgeCheck(buffer = Buffer.alloc(0 , 0 , 'hex')) {
    let messageBody = getMessageBody(buffer)
    let sum = 0
    for (let i = 0; i < messageBody.length; i++)
        sum += messageBody[i]
    let buffer1 = Buffer.alloc(1); // 创建一个1字节的buffer
    // 将数的低8位存入Buffer中
    buffer1[0] = sum & 0xFF;
    if (buffer1[0] === 255) {
        console.log("校验位:" + buffer1.toString('hex') + '  校验通过')
        return true
    } else {
        console.log("校验位:" + buffer1.toString('hex') + '  校验不通过')
        return false
    }


}
function getDataLength(buffer = Buffer.alloc(0, 0, "hex")) {

}

/**
 * 获取报文的数据标识（可能会出BUG，因为一包数据可能发送不完）
 * @param buffer
 * @returns {number}
 */
function getDataFlag(buffer = Buffer.alloc(0, 0, "hex")) {
    return buffer2Num(buffer , 'UINT8' ,2 , 3 )
}

/**
 * 获取报文的设备编号
 * @param buffer
 * @returns {number}
 */
function getEquipNum(buffer = Buffer.alloc(0, 0, "hex")) {
    return buffer2Num(buffer , 'UINT8' ,3 , 4 )
}

/**
 * UTC时间向北京时间的转换（其实就差个8）
 * UTC: Coordinated Universal Time（协调世界时）
 * BJT: Beijing Time（北京时间）
 * @param utcTimeString
 * @returns {Date}
 * @constructor
 */
function UTCToBJT(utcTimeString) {
    // 分割时间字符串
    const hours = parseInt(utcTimeString.slice(0, 2));
    const minutes = parseInt(utcTimeString.slice(2, 4));
    const seconds = parseInt(utcTimeString.slice(4, 6));
    const milliseconds = parseInt(utcTimeString.slice(7, 10));
    // 创建一个当前日期的 UTC 时间对象
    const now = new Date();
    now.setUTCHours(hours, minutes, seconds, milliseconds);
    // 增加 8 小时的偏移量
    // console.log(now)
    // now.setHours(now.getHours() + 8);
    return now
}

/**
 * GPS信息标准化函数
 * @param GPSOriginal
 * @returns {string}
 * @constructor
 */
function GPSFormat(GPSOriginal = '') {
    return parseInt(parseFloat(GPSOriginal)/100)  +  parseFloat(GPSOriginal) % 100 / 60
}
module.exports = {
    num2Buffer,
    obj2buffer,
    buffer2Num,
    buffer2String,
    readyToSend,
    findUnassigned,
    getBufferLength,
    printObj,
    printBuffer,
    splitBuffer,
    getMessageHeader,
    getMessageBody,
    getMessageParams,
    getMessageParamsType,
    getCheck,
    judgeCheck,
    getDataFlag,
    getEquipNum,
    UTCToBJT,
    GPSFormat,
    getCheckNormal
}